goog.require('dkpoints.menu.Menu');

goog.require('goog.testing.jsunit');

var user = null,
    menu = null,
    menuContent = null,
    expectedButtonIDs = null,
    adminButtonIDs = null;


/**
 * When reading the innerHTML of an element, IE capitalizes tag names, so
 * testing directly against a string can be wrong.
 * @param {string} text The text to transform.
 * @return {string} The transformed text.
 */
var normalizeLinkTagCapitalization = function(text) {
  return text.replace('<A href', '<a href').replace('</A>', '</a>');
};

var setUpPage = function() {
  user = document.getElementById('user');
  menuContent = document.getElementById('menu_content');

  adminButtonIDs = [
    'raid',
    'merge',
    'adjustments',
    '', // The separator.
    'tiers'
  ];

  var i = adminButtonIDs.length;
  while (i--) {
    var id = adminButtonIDs[i];
    adminButtonIDs[i] = (id === '') ? '' : 'admin_' + id + '_menuitem';
  }

  expectedButtonIDs = [
    'admin',
    'standings',
    'raids',
    'raiders',
    'items',
    'adjustments',
    'logs',
    'labs'
  ];

  i = expectedButtonIDs.length;
  while (i--) {
    expectedButtonIDs[i] += '_menu_button';
  }
};

var setUp = function() {
  menu = new dkpoints.menu.Menu(menuContent);
};

/* First test login/logout message templates so we can ignore them later. */

// Check that, when the user is authenticated, they are shown a logout message
// with their character name.
var testAuthenticatedUserMessage = function() {
  var expected = 'Logged in as: Russ <a href="/#/auth/logout/">(logout)</a>',
      message = dkpoints.menu.templates.authenticated({character: 'Russ'});

  assertEquals('Expect to be shown a log-out message w/ character name.',
               expected, message);
};

// Check that, when the user is not logged in, they see a log-in prompt.
var testNonAuthenticatedUserMessage = function() {
  var expected = '<a href="/#/auth/login/">Log in</a>',
      message = dkpoints.menu.templates.notAuthenticated({});

  assertEquals('Expect to be shown a login message.',
               expected, message);
};

// Make sure the buttons initialized in the expected order.
var testMenuButtonsMatchExpected = function() {
  var menuButtonElements = menu.buttons_,
      menuButtonComponents = menu.buttonComponents_,
      numExpected = expectedButtonIDs.length,
      i = numExpected;

  assertEquals('There should be exactly ' + numExpected +
               ' buttons in menu.buttons_.',
               numExpected, menuButtonElements.length);
  assertEquals('There should be exactly ' + numExpected +
               ' buttons in menu.buttonComponents_.',
               numExpected, menuButtonComponents.length);

  while (i--) {
    var expectedID = expectedButtonIDs[i],
        nextButtonEl = menuButtonElements[i],
        nextButtonComp = menuButtonComponents[i],
        buttonCompEl = nextButtonComp.getElement(),
        actualID = nextButtonEl.id;

    assertEquals('Button element ' + i + ' should match expected button.',
                 expectedID, actualID);
    assertEquals('Button component ' + i + ' should match the button element.',
                 buttonCompEl.id, nextButtonEl.id);
  }
};

// Check that all of the menu buttons have the proper collapse css class.
var testMenuCollapseClassesSet = function() {
  var i = expectedButtonIDs.length,
      left = 'goog-custom-button-collapse-left',
      right = 'goog-custom-button-collapse-right',
      both = left + ' ' + right,
      buttons = menu.buttons_;

  while (i--) {
    var expectedClass,
        id = buttons[i].id,
        buttonClass = buttons[i].getAttribute('class');
    switch (i) {
      case expectedButtonIDs.length - 1: // The last button collapses left.
        expectedClass = left;
        break;
      case 1: // First user button collapses on the right when admin is hidden.
        expectedClass = right;
        break;
      case 0: // The menu button class has a different name.
        expectedClass = 'goog-menu-button-collapse-right';
        break;
      default:
        expectedClass = both;
        break;
    }

    assertTrue('Button ' + id + ' should have class ' + expectedClass,
               buttonClass.indexOf(expectedClass) !== -1);
  }
};

// Check that the admin menu button is hidden on initialization.
var testAdminMenuHiddenOnInit = function() {
  var adminID = expectedButtonIDs[0],
      adminEl = document.getElementById(adminID),
      nextButtonClasses = menu.buttons_[1].getAttribute('class'),
      expectedClass = 'admin_menu_hidden',
      collapsedClass = 'goog-custom-button-collapse-right';

  assertContains(expectedClass + ' should be in the button\'s class list.',
                 expectedClass, adminEl.getAttribute('class').split(' '));
  assertContains('The second button should be collapsed on the right side only',
                 collapsedClass, nextButtonClasses.split(' '));
};

// Check test that clicking an admin menu button redirects to the right hash.
var testAdminMenuItemsRedirectProperly = function() {
  var realSetLocationHash = dkpoints.utils.setLocationHash,
      redirectHash = '',
      adminChildButton = null,
      i = adminButtonIDs.length,
      redirects = 0,
      expectedRedirects = i - 1; // Ignore the separator.

  dkpoints.utils.setLocationHash = function(hash) {
    redirectHash = hash;
    ++redirects;
  };

  while (i--) {
    var id = adminButtonIDs[i];

    if (id !== '') {
      var expectedHash = '/admin/' + id.split('_')[1];
      menu.handleAdminMenu({target: { getId: function() { return id; } }});

      assertEquals('Clicking ' + id + ' should send us to ' + expectedHash,
                   expectedHash, redirectHash);
    }
  }

  assertEquals('Number of redirects should be ' + expectedRedirects,
               expectedRedirects, redirects);
  dkpoints.utils.setLocationHash = realSetLocationHash;
};

// Test that clicking the normal user buttons redirect to the right hash.
var testUserButtonsRedirectProperly = function() {
  var realSetLocationHash = dkpoints.utils.setLocationHash,
      len = expectedButtonIDs.length,
      buttons = menu.buttonComponents_,
      redirectHash = '',
      redirects = 0,
      expectedRedirects = len - 1;

  dkpoints.utils.setLocationHash = function(hash) {
    redirectHash = hash;
    ++redirects;
  }

  // Skip the admin menu button.
  for (var i = 1; i < len; ++i) {
    var button = buttons[i],
        id = button.getId(),
        expectedHash = '/' + id.substr(0, id.indexOf('_'));

    buttons[i].dispatchEvent(goog.ui.Component.EventType.ACTION);
    assertEquals('Clicking ' + id + ' should send us to ' + expectedHash,
                 expectedHash, redirectHash);
  }

  assertEquals('Should have encountered ' + expectedRedirects + ' redirects.',
               expectedRedirects, redirects);
  dkpoints.utils.setLocationHash = realSetLocationHash;
};

/*
 * Test setAuthStatus for the following transitions:
 *    No status => Not user - testInitialSetAuthToNoLogIn
 *    No status => No-auth user - testInitialSetAuthToNoAuthUser
 *    No status => Admin user - testInitialSetAuthToAdminUser
 *    No user => No-auth user - testTransitionNoUserToNoAuthUser
 *    Not user => Admin user - testTransitionNoUserToAdminUser
 *    No-auth user => No user - testTransitionNoAuthUserToNoUser
 *    No-auth user => Admin user - testTransitionNoAuthUserToAdminUser
 *    Admin user => No-auth user - testTransitionAdminUserToNoAuthUser
 *    Admin user => No user - testTransitionAdminUserToNoUser
 */

/*
 * No status => Not logged in.  Test:
 *  - Should see login message.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testInitialSetAuthToNoLogIn = function() {
  var auth = {
    loggedIn: false,
    isAdmin: false,
    character: ''
  };
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.notAuthenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log-in message in the user panel.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

/*
 * No status => No-auth user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testInitialSetAuthToNoAuthUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: false,
    character: 'Russ'
  };

  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

/*
 * No status => Admin user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu visible; first user button collapsed on both sides.
 */
var testInitialSetAuthToAdminUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: true,
    character: 'Russ'
  };

  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should not be hidden.',
             adminButtonClasses.indexOf(adminHidden) === -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) > -1);
};

/*
 * Not logged in => No-auth user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testTransitionNoUserToNoAuthUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: false,
    character: 'Russ'
  };

  // Set initial to no user.
  menu.setAuthStatus({});

  // Transition to no-auth user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

/*
 * No user => Admin user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu visible; first user button collapsed on both sides.
 */
var testTransitionNoUserToAdminUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: true,
    character: 'Russ'
  };

  // Set to initial no user.
  menu.setAuthStatus({});

  // Transition to auth user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should not be hidden.',
             adminButtonClasses.indexOf(adminHidden) === -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) > -1);
};

/*
 * No-auth user => Not logged in.  Test:
 *  - Should see login message.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testTransitionNoAuthUserToNoUser = function() {
  var auth = {};

  // Set initial to no-auth user.
  menu.setAuthStatus({
    loggedIn: true,
    isAdmin: false,
    character: 'Russ'
  });

  // Transition to no user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.notAuthenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log-in message in the user panel.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

/*
 * No-auth user => Admin user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu visible; first user button collapsed on both sides.
 */
var testTransitionNoAuthUserToAdminUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: true,
    character: 'Russ'
  };

  // Set to initial no-auth user.
  menu.setAuthStatus({
    loggedIn: true,
    isAdmin: false,
    character: 'Russ'
  });

  // Transition to admin user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should not be hidden.',
             adminButtonClasses.indexOf(adminHidden) === -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) > -1);
};

/*
 * Admin user => No-auth user.  Test:
 *  - Should see log-out message w/ our name.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testTransitionAdminUserToNoAuthUser = function() {
  var auth = {
    loggedIn: true,
    isAdmin: false,
    character: 'Russ'
  };

  // Set initial to no user.
  menu.setAuthStatus({
    loggedIn: true,
    isAdmin: true,
    character: 'Russ'
  });

  // Transition to no-auth user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.authenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log out message with our name.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

/*
 * Admin user => No user.  Test:
 *  - Should see login message.
 *  - Admin menu hidden; first user button collapsed only on the right.
 */
var testTransitionAdminUserToNoUser = function() {
  var auth = {};

  // Set initial to admin user.
  menu.setAuthStatus({
    loggedIn: true,
    isAdmin: true,
    character: 'Russ'
  });

  // Transition to no user.
  menu.setAuthStatus(auth);

  var expectedUserMessage = dkpoints.menu.templates.notAuthenticated(auth);
  var userElText = normalizeLinkTagCapitalization(user.innerHTML);
  assertEquals('We should see a log-in message in the user panel.',
               expectedUserMessage, userElText);

  var adminButtonClasses = menu.buttons_[0].getAttribute('class'),
      userButtonClasses = menu.buttons_[1].getAttribute('class'),
      adminHidden = 'admin_menu_hidden',
      collapsedRight = 'goog-custom-button-collapse-right',
      collapsedLeft = 'goog-custom-button-collapse-left';

  assertTrue('Admin menu should be hidden.',
             adminButtonClasses.indexOf(adminHidden) > -1);

  assertTrue('The first user button should be collapsed on the right.',
             userButtonClasses.indexOf(collapsedRight) > -1);

  assertTrue('The first user button should not be collapsed on the left.',
             userButtonClasses.indexOf(collapsedLeft) === -1);
};

var tearDown = function() {
  menu = null;
  user.innerHTML = menuContent.innerHTML = '';
};
